package com.sy.simpleegg

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Process
import android.view.KeyEvent
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.lifecycleScope
import com.sy.simpleegg.base.BaseMvpActivity
import com.sy.simpleegg.bean.CashConfigBean
import com.sy.simpleegg.bean.CheckMoneyBean
import com.sy.simpleegg.bean.MotorConfigBean
import com.sy.simpleegg.bean.OrderVerifyResult
import com.sy.simpleegg.bean.RegDataBean
import com.sy.simpleegg.bean.RepCashDataBean
import com.sy.simpleegg.bean.RepCoinDataBean
import com.sy.simpleegg.bean.SaveMoneyBean
import com.sy.simpleegg.bean.SupplementOrderBean
import com.sy.simpleegg.config.Config
import com.sy.simpleegg.config.Config.REG_EVENT
import com.sy.simpleegg.constant.Constant
import com.sy.simpleegg.constant.ControlBoard
import com.sy.simpleegg.constant.MultPlatform
import com.sy.simpleegg.constant.OutMode
import com.sy.simpleegg.constant.ProductType
import com.sy.simpleegg.databinding.ActivityMainBinding
import com.sy.simpleegg.event.BanknoteEvent
import com.sy.simpleegg.event.ClearCoinsEvent
import com.sy.simpleegg.event.ControllerHeartBeatEvent
import com.sy.simpleegg.event.DevRegisterEvent
import com.sy.simpleegg.event.DispenserOrderEvent
import com.sy.simpleegg.event.ExitAppEvent
import com.sy.simpleegg.event.GetDeviceIdleEvent
import com.sy.simpleegg.event.GetDeviceIdleRespEvent
import com.sy.simpleegg.event.GetLoginCodeEvent
import com.sy.simpleegg.event.GetPayCodeEvent
import com.sy.simpleegg.event.GetWithdrawalCodeEvent
import com.sy.simpleegg.event.LyyBoxHeartBeatEvent
import com.sy.simpleegg.event.OutCoinsEvent
import com.sy.simpleegg.event.PlaceCashOrderEvent
import com.sy.simpleegg.event.PlaceLocalWithdrawalOrderEvent
import com.sy.simpleegg.event.PlaceLocalWithdrawalOrderRespEvent
import com.sy.simpleegg.event.PlaceOrderEvent
import com.sy.simpleegg.event.PostBackscanPayEvent
import com.sy.simpleegg.event.PostCashEvent
import com.sy.simpleegg.event.PostResultEvent
import com.sy.simpleegg.event.PostWriteOffDataEvent
import com.sy.simpleegg.event.QueryLgLoginCancelEvent
import com.sy.simpleegg.event.QueryPlaceOrderCancelEvent
import com.sy.simpleegg.event.RecBasicConfigEvent
import com.sy.simpleegg.event.RecCashConfigEvent
import com.sy.simpleegg.event.RecMotorConfigEvent
import com.sy.simpleegg.event.ReceiveOrderEvent
import com.sy.simpleegg.event.ReceiveOrderKkbHttpEvent
import com.sy.simpleegg.event.ReceiveWithdrawalOrderEvent
import com.sy.simpleegg.event.ReceiveOrderYchHttpEvent
import com.sy.simpleegg.event.ReceiveWriteOffOrderEvent
import com.sy.simpleegg.event.RefreshBasicConfigEvent
import com.sy.simpleegg.event.RefreshCashConfigEvent
import com.sy.simpleegg.event.RefreshCashDataEvent
import com.sy.simpleegg.event.RefreshCoinsEvent
import com.sy.simpleegg.event.RefreshDeviceNumberEvent
import com.sy.simpleegg.event.RefreshGoodsEvent
import com.sy.simpleegg.event.RefreshMotorConfigEvent
import com.sy.simpleegg.event.RefreshSignalEvent
import com.sy.simpleegg.event.RepSaveCoinDataEvent
import com.sy.simpleegg.event.ResetMotorEvent
import com.sy.simpleegg.event.SaveBasicConfigEvent
import com.sy.simpleegg.event.SaveCashConfigEvent
import com.sy.simpleegg.event.SaveCoinEvent
import com.sy.simpleegg.event.SaveMotorConfigEvent
import com.sy.simpleegg.event.ScanEvent
import com.sy.simpleegg.event.ShowCodeEvent
import com.sy.simpleegg.event.ShowPayQrCodeEvent
import com.sy.simpleegg.event.StartClearCoinsEvent
import com.sy.simpleegg.event.StopClearCoinsEvent
import com.sy.simpleegg.event.SupplementCoinsEvent
import com.sy.simpleegg.event.SupplementEvent
import com.sy.simpleegg.event.SwitchFragmentEvent
import com.sy.simpleegg.event.UserLoginEvent
import com.sy.simpleegg.event.UserLoginKkbEvent
import com.sy.simpleegg.event.UserLoginYchEvent
import com.sy.simpleegg.event.WirteOffResultEvent
import com.sy.simpleegg.ext.getDeviceStatus
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.ext.showToastMsg
import com.sy.simpleegg.mvp.contract.MainContract
import com.sy.simpleegg.mvp.presenter.MainPresenter
import com.sy.simpleegg.platform.BackstagePlatform
import com.sy.simpleegg.platform.MainManager
import com.sy.simpleegg.platform.defmqtt.bean.DefMqttParam
import com.sy.simpleegg.platform.kkb.bean.KkbSdkParam
import com.sy.simpleegg.platform.kkb.bean.RecieveOrderKkbBean
import com.sy.simpleegg.platform.kkb.bean.member.KkbQrCodeMemberInfoResponse
import com.sy.simpleegg.platform.lyybox.bean.LyyBoxParam
import com.sy.simpleegg.platform.lyysdk.bean.LyySdkParam
import com.sy.simpleegg.platform.whm.bean.WhmMqttParam
import com.sy.simpleegg.platform.whmhex.bean.WhmMqttHexParam
import com.sy.simpleegg.platform.ychsdk.bean.RecieveOrderYchBean
import com.sy.simpleegg.platform.ychsdk.bean.YchSdkParam
import com.sy.simpleegg.platform.ychsdk.bean.member.QrCodeMemberInfoResponse
import com.sy.simpleegg.serialport.CoinManager
import com.sy.simpleegg.serialport.backscan.BackscanController
import com.sy.simpleegg.serialport.backscan.ScanType
import com.sy.simpleegg.serialport.backscan.usb.ScanGunHelper
import com.sy.simpleegg.serialport.banknote.BanknoteController
import com.sy.simpleegg.serialport.coincontroller.bean.CoinControlFixParam
import com.sy.simpleegg.serialport.sycontroller.bean.CoinControlParam
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidParam
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyyParam
import com.sy.simpleegg.ui.dialog.SupplementDialog
import com.sy.simpleegg.ui.fragment.BackstageFragment
import com.sy.simpleegg.ui.fragment.HomeFragment
import com.sy.simpleegg.ui.fragment.config.FragmentEnum
import com.sy.simpleegg.util.BoardApiUtil
import com.sy.simpleegg.util.ByteUtil
import com.sy.simpleegg.util.CommonUtil
import com.sy.simpleegg.util.DateTimeUtil
import com.sy.simpleegg.util.FileUtil
import com.sy.simpleegg.util.GsonUtil
import com.sy.simpleegg.util.Preference
import com.sy.simpleegg.util.SPHelper
import com.sy.mqhexsdk.bean.rec.RecUserInfoNew
import com.sy.simpleegg.serialport.lyyegg.LyyEggController
import com.tbruyelle.rxpermissions2.RxPermissions
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.cnbleu.serialport.SerialPort
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.File
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date

class MainActivity :
    BaseMvpActivity<MainContract.View, MainContract.Presenter, ActivityMainBinding>(),
    MainContract.View {

    private var scanGunHelper: ScanGunHelper? = null
    private var canScan = false
    private var scanType = ScanType.UNDEFINE

    private var supplementDialog: SupplementDialog? = null

    private var outMode = OutMode.NORMAL

    private var checkDevJob: Job? = null
    private var devIdle = false

    /**
     * 默认mq通讯
     */
    private var defmqOpen: Boolean by Preference(
        Constant.SETTING_DEFMQ_OPEN,
        BuildConfig.DEF_MQ_OPEN
    )

    /**
     * lyysdk通讯
     */
    private var lyysdkOpen: Boolean by Preference(
        Constant.SETTING_LYYSDK_OPEN,
        BuildConfig.LYYSDK_OPEN
    )

    /**
     * lyybox通讯
     */
    private var lyyboxOpen: Boolean by Preference(
        Constant.SETTING_LYYBOX_OPEN,
        BuildConfig.LYYBOX_OPEN
    )

    /**
     * 接入第三方平台
     */
    private var platform: BackstagePlatform by Preference(
        Constant.SETTING_OTHER_PLATFORM,
        BackstagePlatform.WHM_MQTT_HEX
    )

    /**
     * 国家地区
     */
    private var country: Int by Preference(Constant.SETTING_COUNTRY, Config.DEFAULT_COUNTRY_CODE)

    /**
     * 设备登录二维码
     */
    private var loginCode: String by Preference(Constant.SETTING_LOGIN_CODE, "")
    /**
     * 设备提币二维码
     */
    private var withdrawalCode: String by Preference(Constant.SETTING_WITHDRAWAL_CODE, "")
    /**
     * 设备消费二维码
     */
    private var devConsumeCode: String by Preference(Constant.SETTING_CONSUME_CODE, "")
    /**
     * KKB商户识别码
     */
    private var kkbIdentity: String by Preference(Constant.SETTING_KKB_IDENTITY, "")
    /**
     * 开启多平台
     */
    private var openMultPlatform: MultPlatform by Preference(Constant.SETTING_OPEN_MULT_PLATFORM, MultPlatform.OPEN)
    /**
     * 多平台的主平台设备编号
     */
    private var mainDeviceNumber: String by Preference(Constant.SETTING_MAIN_DEVICE_NUMBER, "")
    /**
     * 订单自动补币
     * 开启后设备出币异常时会停止设备运行，并在启动时自动处理未出币订单
     * 关闭后设备出币异常后可以继续正常运行，出币异常订单会记录在后台页面，可以手动选择订单补币
     */
    private var orderSupplement: Boolean by Preference(Constant.SETTING_ORDER_SUPPLEMENT, false)
    /**
     * 设备状态 true-正常 false-故障
     */
    private var deviceStatus: Boolean by Preference(Constant.SETTING_DEVICE_STATUS, true)

    private var mIndex = FragmentEnum.HOME

    private var homeFragment: HomeFragment? = null
    private var backstageFragment: BackstageFragment? = null

    //    private var controller: SyController? = null
//    private var coinController: SyBusinessController? = null
//    private var coinController: CoinController? = null
    private var coinController: CoinManager? = null
    private var banknoteController: BanknoteController? = null
    private var backscanController: BackscanController? = null
    private var eggController: LyyEggController? = null

    private var signalJob: Job? = null
    private var isLoop = true

    private var permissionAvaliable = false

    private var backstageManager: MainManager? = null

    private var clearCoins = 0L
    private var clearCoinsFinish = false

    // 日志保留时间：7天
    private val logSaveTime = 7L * 24L * 60L * 60L * 1000L

    private var respBasicConfigSnHex = ""
    private var respCashConfigSnHex = ""
    private var respMotorConfigSnHex = ""

    private var clearOrderNumber = ""


    override fun createPresenter(): MainContract.Presenter = MainPresenter(lifecycleScope)

    override fun getViewBinding(): ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)

    override fun attachLayoutRes(): Int = R.layout.activity_main

    override fun initView() {
        super.initView()
        initGlobleConfig()
        showFragment(mIndex)
    }

    override fun initData() {
        initPermissions()
        initSignalJob()
    }

    override fun initOther() {
        //权限检测
        mPresenter?.init()
        mPresenter?.initMqtt()
        mPresenter?.initDeviceSerialport()

//        lifecycleScope.launch(Dispatchers.Main) {
//            withContext(Dispatchers.IO) {
////                initConfig()
//            }
//
//        }
        lifecycleScope.launch(Dispatchers.Main) {
            withContext(Dispatchers.IO) {
                while (!permissionAvaliable) {
                    delay(1000)
                }
            }
            initDev()
        }
    }

    override fun checkMoneyResult(result: CheckMoneyBean) {
        try {
            if (!result.result) {
                showToastMsg(result.msg)
            }
            lifecycleScope.launch {
                delay(100)
                coinController?.canSaveMoney(result.result)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("校验纸钞获取币数结果处理异常：${e.message}")
        }
    }

    override fun saveMoneyResult(result: SaveMoneyBean?) {
        result?.let {
            EventBus.getDefault()
                .post(RefreshCashDataEvent(it.checkMoney.toLong(), it.money.toLong()))
        }
    }

    override fun postCashData(repData: Any) {
        EventBus.getDefault().post(PostCashEvent(repData))
    }

    override fun reportSaveCoinData(repCoinDataBean: RepCoinDataBean) {
        backstageManager?.uploadSaveCoinData(repCoinDataBean)
    }

    override fun saveWithdrawalCoinOrderResult(orderData: Any?) {
        orderData?.let {
            EventBus.getDefault().post(ReceiveWithdrawalOrderEvent(platform, it))
            return
        }
    }

    override fun saveWriteOffOrderResult(orderData: Any) {
        EventBus.getDefault().post(ReceiveWriteOffOrderEvent(platform, orderData))
    }

    override fun loadSupplementData(datas: MutableList<SupplementOrderBean>) {
        logFile("MainActivity加载出币异常订单")
        if (datas.isEmpty()) return
        showSupplementDialog(datas)
    }

    override fun verifyOrder(orderVerifyResult: OrderVerifyResult?) {
        orderVerifyResult?.let { result ->
            EventBus.getDefault().post(ReceiveOrderEvent(result.platform, result.orderData))
        }
    }

    override fun createOneCoinOrder(repCashDataBean: RepCashDataBean?) {
        repCashDataBean?.let {
            EventBus.getDefault().post(DispenserOrderEvent(platform, it))
        }
    }

    override fun restartScan() {
        openScan(true)
    }

    override fun out() {
        eggController?.out()
    }

    override fun showLoading() {

    }

    override fun hideLoading() {

    }

    override fun onDestroy() {
//        stopMqService()
        closeSerialport()
        super.onDestroy()
        isLoop = false
        signalJob?.cancel()
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        if (event.deviceId > 0 && canScan) {
            scanGunHelper?.let {
                it.analysisKeyEvent(event)
                return true
            }
        }
        return super.dispatchKeyEvent(event)
    }

    private fun initGlobleConfig(){
        mPresenter?.initCashPackageData(platform)
        Config.CURRENCY_SYMBOLS = CommonUtil.getCurrencySymbols(country)
        Config.PRODUCT_TYPE = when (SPHelper.getGoodType()){
            3 -> ProductType.CURRENCY
            4 -> ProductType.BEAD
            else -> ProductType.CURRENCY
        }
        Config.OPEN_MULT_PLATFORM = openMultPlatform
        Config.ORDER_SUPPLEMENT = orderSupplement
        Config.DEVICE_STATUS = deviceStatus
    }

    /**
     * 显示Fragment
     * @param index 要显示的Fragment
     */
    private fun showFragment(index: FragmentEnum) {
        val transaction = supportFragmentManager.beginTransaction()
        hideFragment(transaction)
        mIndex = index
        when (index) {
            FragmentEnum.HOME -> {
                if (homeFragment == null) {
                    homeFragment = HomeFragment.getInstance()
                    transaction.add(R.id.main_container, homeFragment!!, "home")
                } else {
                    transaction.show(homeFragment!!)
                }
            }

            FragmentEnum.BACKSTAGE_MAIN -> {
                if (backstageFragment == null) {
                    backstageFragment = BackstageFragment.getInstance()
                    transaction.add(R.id.main_container, backstageFragment!!, "backstage")
                } else {
                    transaction.show(backstageFragment!!)
                }
            }
        }
        transaction.commit()
    }

    /**
     * 隐藏Fragment
     * @param transaction Fragment管理器
     */
    private fun hideFragment(transaction: FragmentTransaction) {
        homeFragment?.let { transaction.hide(it) }
        backstageFragment?.let {
            transaction.remove(it)
            backstageFragment = null
        }
    }

    /**
     * 关闭串口
     */
    private fun closeSerialport() {
//        controller?.close()
        coinController?.release()
        backscanController?.close()
        banknoteController?.close()
    }

    /**
     * 网络信号获取
     */
    private fun initSignalJob() {
        signalJob?.cancel()
        signalJob = lifecycleScope.launch(Dispatchers.IO) {
            var count = 0L
            while (isLoop) {
                try {
                    val signalStr = BoardApiUtil.getDeviceNetSignal()
                    val params = signalStr.split(",")
                    val type = params[0]
                    val signal = params[1].toInt()
                    val signalLevel = when {
                        signal < 20 -> 1
                        signal in 20 until 40 -> 2
                        signal in 40 until 60 -> 3
                        signal in 60 until 80 -> 4
                        signal >= 80 -> 5
                        else -> {
                            5
                        }
                    }

                    Constant.NETWORK_TYPE = when (type){
                        "WIFI" -> type
                        else -> "4G"
                    }
                    Constant.NETWORK_SIGNAL = signal
                    val isConnected = BoardApiUtil.isNetworkAvailable()
                    EventBus.getDefault().post(RefreshSignalEvent(type, signalLevel, isConnected))
                    count++
                    if (count > 10) {
                        delay(30000)
                    } else {
                        delay(5000)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    logFile("获取信号异常：${e.message}")
                }
            }
        }
    }

    /**
     * 获取权限
     */
    private fun initPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val rxPermissions = RxPermissions(this)
            val subscribe: Disposable = rxPermissions.request(
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.REORDER_TASKS //                            , Manifest.permission.CAMERA
            )
                .subscribe(Consumer<Boolean> { granted ->
                    if (granted) {
                        //打开悬浮窗权限设置页
//                        if (!checkFloatPermission(getApplicationContext())) {
//                            showToast("请给软件设置权限，否则无法正常使用！")
//                            val intent = Intent(Settings.ACTION_SETTINGS)
//                            startActivity(intent)
//                        } else {
//                            //所有权限都授予
//                            initConfig()
//                        }
                        permissionAvaliable = true
                        //                                initConfig();
                    } else {
                        //至少一个权限没有被授予
//                                ToastUtils.setBgColor(0xff000000);
//                                ToastUtils.showLong("请先获取应用权限");
                        showToast("请先获取应用权限")
                        CoroutineScope(Dispatchers.IO).launch {
                            delay(3000)
                            exit()
                        }
                    }
                })
        } else {
            //打开悬浮窗权限设置页
            permissionAvaliable = true
        }
    }

    /**
     * 初始化设备
     */
    private fun initDev() {
        initSourceDir()
        writeDevInfo()
        clearLogFiles()
        initMqtt()
        initSerialPort()
        initLocation()
        checkSupplement()
        registReceiver()

//        lifecycleScope.launch(Dispatchers.IO) {
//            delay(5000)
////            mPresenter?.receiveScanOrder("Q.123456.A")
//            val apkFile = File("/storage/emulated/0/whm_download/AEGH0001/1.apk")
//            val isExist = apkFile.exists()
//            logFile("apk文件：${if (isExist) "存在" else "不存在"}")
//            BoardApiUtil.installSilence("/storage/emulated/0/whm_download/AEGH0001/1.apk")
//        }
    }

    override fun rebootDaily(){
        isDeviceIdle(1, "", "")
    }

    private fun initSourceDir() {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                try {
                    File(Config.DEF_MEDIA_PATH).apply {
                        if (!exists()) {
                            mkdirs()
                        }
                    }
                    File(Config.DEF_LOGO_PATH).apply {
                        if (!exists()) {
                            mkdirs()
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    logFile("初始化资源路径异常：${e.message}")
                }
            }
        }
    }

    private fun writeDevInfo() {
        lifecycleScope.launch {
            try {
                BoardApiUtil.getDeviceInfo(applicationContext)?.let {
                    val sb = StringBuffer()
                    for ((key, value) in it) {
                        sb.append("$key = $value\r\n")
                    }
                    sb.append("app_version = ")
                        .append(BoardApiUtil.getVersionName(applicationContext)).append("\n")
                    logFile("设备信息：$sb")
                }
            } catch (e: Exception) {
                e.printStackTrace()
                logFile("获取设备信息异常：${e.message}")
            }
        }
    }

    @SuppressLint("SimpleDateFormat")
    private fun clearLogFiles() {
        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val folder = Config.LOG_PATH
                val file = File(folder)
                val files = file.listFiles()
                if (files != null) {
                    val systime = System.currentTimeMillis()
                    for (f in files) {
                        if (f.isFile) {
                            val modifiedTime = f.lastModified()
                            if (systime - modifiedTime > logSaveTime //                                    || f.length() >= 50 * 1048576
                            ) {
                                FileUtil.delete(f.absolutePath)
                            }
                        } else if (f.isDirectory) {
                            val fName = f.name
                            try {
                                val date: Date? = SimpleDateFormat("yyyyMMdd").parse(fName)
                                if (date == null) {
                                    FileUtil.deleteDirectory(f.absolutePath)
                                    break
                                }
                                val dirTime = date.time
                                if (systime - dirTime > logSaveTime) {
                                    FileUtil.deleteDirectory(f.absolutePath)
                                }
                            } catch (e: ParseException) {
                                e.printStackTrace()
                                FileUtil.deleteDirectory(f.absolutePath)
                            }
                        }
                    }
                }

                val apkFilePath = Config.DOWNLOAD_PATH
                val apkFile = File(apkFilePath)
                if (apkFile.exists()) {
                    FileUtil.delete(apkFilePath)
                }

            } catch (e: java.lang.Exception) {
                e.printStackTrace()
                logFile("清理日志文件异常：" + e.message)
            }
        }
    }

    /**
     * 开启mqtt
     */
    private fun initMqtt() {
        if (backstageManager != null) {
            return
        }
        val deviceId = BoardApiUtil.getDeviceId()!!
//        val deviceId = "dbjf4efef9a9b666290"
//        val deviceId = "f4efef9a9b666290"//a6221abbc6a42df3
//        val deviceId = "a6221abbc6a42df3"//a6221abbc6a42df3
//        val deviceId = "99d410aba97a11b5"//a6221abbc6a42df3
//        val deviceId = "477d646b82a652e2"//a6221abbc6a42df3
        logFile("deviceId=$deviceId")

        var defMqParam: DefMqttParam? = null
        var lyySdkParam: LyySdkParam? = null
        var lyyBoxParam: LyyBoxParam? = null
        var whmMqttParam: WhmMqttParam? = null
        var whmMqttHexParam: WhmMqttHexParam? = null
        var ychSdkParam: YchSdkParam? = null
        var kkbSdkParam: KkbSdkParam? = null

        when (platform) {
            BackstagePlatform.DEF_MQTT -> {

            }

            BackstagePlatform.LYY_SDK -> {
                lyySdkParam = createLyySdkParam(deviceId)
                lyyBoxParam = createLyyBoxParam(deviceId)
                when (Config.OPEN_MULT_PLATFORM){
                    MultPlatform.OPEN -> whmMqttHexParam = createWhmMqttHexParam(deviceId)
                    MultPlatform.CLOSE -> {}
                }
            }

            BackstagePlatform.LYY_BOX -> {
                lyySdkParam = createLyySdkParam(deviceId)
                lyyBoxParam = createLyyBoxParam(deviceId)
            }

            BackstagePlatform.WHM_MQTT -> {

            }

            BackstagePlatform.WHM_MQTT_HEX -> {
                whmMqttHexParam = createWhmMqttHexParam(deviceId)
//                whmMqttHexParam = createWhmMqttHexParam("415c91471060dd25")
            }

            BackstagePlatform.YCH_SDK -> {
                ychSdkParam = createYchSdkParam(deviceId)
                when (Config.OPEN_MULT_PLATFORM){
                    MultPlatform.OPEN -> whmMqttHexParam = createWhmMqttHexParam(deviceId)
                    MultPlatform.CLOSE -> {}
                }
            }

            BackstagePlatform.KKB -> {
                kkbSdkParam = createKkbSdkParam(deviceId)
                when (Config.OPEN_MULT_PLATFORM){
                    MultPlatform.OPEN -> whmMqttHexParam = createWhmMqttHexParam(deviceId)
                    MultPlatform.CLOSE -> {}
                }
            }
        }

        kkbSdkParam?.let {
            if (it.ssid.isEmpty()){
                showToast("请配置商户识别码")
                logFile("KKB商户识别码未配置")
            }
        }

        backstageManager = MainManager(
            applicationContext,
            defMqParam,
            lyySdkParam,
            lyyBoxParam,
            whmMqttParam,
            whmMqttHexParam,
            ychSdkParam,
            kkbSdkParam,
            object : MainManager.OnBackstageCallback {
                override fun toLogin() {

                }

                override fun onLoginSuccess(pf: BackstagePlatform, devNumber: String?) {
                    when (Config.OPEN_MULT_PLATFORM){
                        MultPlatform.OPEN -> {
                            //开启多平台，记录主平台的设备编号
                            if (pf == BackstagePlatform.WHM_MQTT_HEX){
                                mainDeviceNumber = devNumber?:""
                            }
                            //开启多平台，辅平台为酷酷宝时，把主平台的设备号当作酷酷宝的设备编号
                            when (pf){
                                BackstagePlatform.DEF_MQTT -> {
                                    devNumber?.let { refreshDevNumber(it) }
                                }
                                BackstagePlatform.LYY_SDK -> {devNumber?.let { refreshDevNumber(it) }}
                                BackstagePlatform.LYY_BOX -> {}
                                BackstagePlatform.WHM_MQTT -> {}
                                BackstagePlatform.WHM_MQTT_HEX -> {
                                    if (platform == BackstagePlatform.KKB || platform == BackstagePlatform.WHM_MQTT_HEX){
                                        //开启多平台，子平台是kkb或者whm
                                        devNumber?.let { refreshDevNumber(it) }
                                    }
                                }
                                BackstagePlatform.YCH_SDK -> {
                                    devNumber?.let { refreshDevNumber(it) }
                                }
                                BackstagePlatform.KKB -> {}
                            }
                        }
                        MultPlatform.CLOSE -> {
                            devNumber?.let { refreshDevNumber(it) }
                        }
                    }
                }

                override fun onConnectionChange(
                    platform: BackstagePlatform,
                    connectState: Boolean
                ) {
                    logFile("onConnectionChange")
                }

                override fun onGetPackage(
                    platform: BackstagePlatform,
                    pkgCount: Int,
                    pkgType: Int
                ) {
                    logFile("onGetPackage")
                }

                override fun onRefreshPackageData(platform: BackstagePlatform, dataList: Any) {
                    logFile("刷新套餐数据")
                    EventBus.getDefault().post(RefreshGoodsEvent(platform, dataList))
                }

                override fun onBillResp(
                    platform: BackstagePlatform,
                    sucess: Boolean,
                    billMsgNumber: String
                ) {
                    logFile("onBillResp:sucess=$sucess billMsgNumber=$billMsgNumber")
                }

                override fun onShowPayCode(
                    platform: BackstagePlatform,
                    codeData: String?,
                    showType: Int
                ) {
                    codeData?.let {
                        EventBus.getDefault().post(ShowPayQrCodeEvent(platform, it))
                    }
                }

                override fun onSaveCoinResult(platform: BackstagePlatform, result: Boolean) {
                    mPresenter?.SaveCoinPostResult(result)
                }

                override fun onConsumeCoinResult(platform: BackstagePlatform, success: Boolean, errMsg: String?, memberId: String?, balance: Long?) {
                    EventBus.getDefault().post(PlaceLocalWithdrawalOrderRespEvent(success, errMsg, memberId, balance))
                }

                override fun onReceiveOrder(platform: BackstagePlatform, orderData: Any) {
                    logFile("支付成功订单号：${GsonUtil.getInstance()?.toJson(orderData)}")
                    //校验订单是否合法（paymentOutInfoDialog != null && order.isPay == PayState.UNPAYED && order.time + 30秒 > currentTime）
                    mPresenter?.verifyOrder(platform, orderData)
                    mPresenter?.paibi()
                }

                override fun onReceiveWithdrawalCoinOrder(
                    platform: BackstagePlatform,
                    orderData: Any,
                ) {
                    logFile("提币订单：orderData=${GsonUtil.getInstance()!!.toJson(orderData)} ")
                    mPresenter?.saveWithdrawalCoinOrder(platform, orderData)
                }

                override fun onReceiveWriteOffOrder(platform: BackstagePlatform, orderData: Any) {
                    logFile("核销订单：orderData=${GsonUtil.getInstance()!!.toJson(orderData)} ")
                    mPresenter?.saveWriteOffOrder(platform, orderData)
                }

                override fun onReceiveOrderYchHttp(
                    platform: BackstagePlatform,
                    orderDataYch: RecieveOrderYchBean,
                    paySuccessed: Boolean
                ) {
                    logFile("油菜花http订单支付结果：${GsonUtil.getInstance()?.toJson(orderDataYch)}")
                    placeOrderSuccessed(platform, orderDataYch.transId, orderDataYch.orderId, orderDataYch.orderNumber, if (paySuccessed) 1 else 2, "", "", "")
                    lifecycleScope.launch {
                        delay(1000)
                        EventBus.getDefault().post(ReceiveOrderYchHttpEvent(platform, orderDataYch))
                    }
                }

                override fun onReceiveOrderKkbHttp(
                    platform: BackstagePlatform,
                    orderDataKkb: RecieveOrderKkbBean,
                    paySuccessed: Boolean
                ) {
                    logFile("酷酷宝http订单支付结果：${GsonUtil.getInstance()?.toJson(orderDataKkb)}")
                    placeOrderSuccessed(platform, orderDataKkb.transId, orderDataKkb.orderId, orderDataKkb.orderNumber, if (paySuccessed) 1 else 2, "", "", "")
                    lifecycleScope.launch {
                        delay(1000)
                        EventBus.getDefault().post(ReceiveOrderKkbHttpEvent(platform, orderDataKkb))
                    }
                }

                override fun onShowTips(platform: BackstagePlatform, colorType: Int, tips: String) {
                    logFile("onShowTips:colorType=$colorType tips=$tips")
                }

                override fun onShowRegist(
                    platform: BackstagePlatform,
                    isShow: Boolean,
                    registCode: String?
                ) {
//                    if (isShow) {
//                        var tips = ""
//                        tips = when (platform) {
//                            BackstagePlatform.DEF_MQTT -> getString(R.string.regist_content)
//                            BackstagePlatform.LYY_SDK -> getString(R.string.regist_content_lyysdk)
//                            BackstagePlatform.LYY_BOX -> getString(R.string.regist_content_lyybox)
//                            BackstagePlatform.WHM_MQTT -> {
//                                ""
//                            }
//                            BackstagePlatform.WHM_MQTT_HEX -> getString(R.string.regist_content_whm_hex)
//                            BackstagePlatform.YCH_SDK -> getString(R.string.regist_content_ychsdk)
//                            BackstagePlatform.KKB -> getString(R.string.regist_content_kkb)
//                        }
//                        registCode?.let {
//                            REG_EVENT = 0
//                            lifecycleScope.launch (Dispatchers.IO){
//                                do {
//                                    EventBus.getDefault().post(DevRegisterEvent(it, tips, 0, true))
//                                    delay(1000)
//                                }while (REG_EVENT != 1)
//                            }
//                        }
//                    } else {
//                        EventBus.getDefault().post(DevRegisterEvent(null, "", 0, false))
//                    }
                }

                override fun lyyRespLyyBoardOutResult(dataHex: String) {
                    logFile("lyyRespLyyBoardOutResult:$dataHex")
                }

                override fun lyyRespListAdd(dataHex: String) {
                    logFile("lyyRespListAdd:$dataHex")
                }

                override fun lyyRespBoxNetwork(dataHex: String) {
                    logFile("lyyRespBoxNetwork:$dataHex")
                }

                override fun lyyCheckBoardConnecton(dataHex: String, uniqueCodeHex: String) {
                    logFile("lyyCheckBoardConnecton:$dataHex")
                }

                override fun lyyGetBoardState(dataHex: String, uniqueCodeHex: String) {
                    logFile("lyyGetBoardState:$dataHex")
                }

                override fun lyyGetBoardConfig(dataHex: String) {
                    logFile("lyyGetBoardConfig:$dataHex")
                }

                override fun lyySetBoardConfig(dataHex: String) {
                    logFile("lyySetBoardConfig:$dataHex")
                }

                override fun lyyBoxHeartBeat(heartBeat: Boolean) {
                    Constant.BOX_HEARTBEAT = heartBeat
                    EventBus.getDefault().post(LyyBoxHeartBeatEvent(heartBeat))
                }

                override fun onRestartApp() {
                    logFile("重启APP")
                    finishAndRemoveTask()
                    Process.killProcess(Process.myPid())
                }

                override fun onRecCashConfig(cashConfigBean: CashConfigBean) {
                    coinController?.setCashConfig(cashConfigBean)
                }

                override fun onRecMotorConfig(motorConfigBean: MotorConfigBean) {
                    coinController?.setMotorConfig(motorConfigBean.forward, motorConfigBean.reverse, motorConfigBean.stopDelay)
                }

                override fun getBasicConfigToResp(snHex: String) {
                    respBasicConfigSnHex = snHex
                    coinController?.getBasicConfig()
                }

                override fun getCashConfigToResp(snHex: String) {
                    respCashConfigSnHex = snHex
                    coinController?.getCashConfig()
                }

                override fun getMotorConfigToResp(snHex: String) {
                    respMotorConfigSnHex = snHex
                    coinController?.getMotorConfig()
                }

                override fun onRecBasicConfig(basicConfigHex: String) {
                    coinController?.setBasicConfig(basicConfigHex)
                }

                override fun onUserLoginDev(recUserInfo: RecUserInfoNew) {
                    EventBus.getDefault().post(UserLoginEvent(recUserInfo))
                }

                override fun onUserLoginDevYch(loginMemberInfo: QrCodeMemberInfoResponse) {
                    EventBus.getDefault().post(UserLoginYchEvent(loginMemberInfo))
                }

                override fun onUserLoginDevKkb(loginMemberInfo: KkbQrCodeMemberInfoResponse) {
                    EventBus.getDefault().post(UserLoginKkbEvent(loginMemberInfo))
                }

                override fun onShowLoginCode(code: String) {
                    loginCode = code
                    EventBus.getDefault().post(ShowCodeEvent(0, code))
                }

                override fun onShowWithdrawalCode(code: String) {
                    withdrawalCode = code
                    EventBus.getDefault().post(ShowCodeEvent(1, code))
                }

                override fun onRecDevConsumeCode(code: String) {
                    devConsumeCode = code
                    EventBus.getDefault().post(ShowCodeEvent(2, code))
                }

                override fun onDevLogoutResp() {
                    logFile("注销登录完成")
                }

                override fun onPlaceOrder(
                    platform: BackstagePlatform,
                    transId: String,
                    orderId: String,
                    orderNumber: String,
                    goodId: String,
                    coins: String,
                    money: String
                ) {
                    placeOrderSuccessed(platform, transId, orderId, orderNumber, 0, goodId, coins, money)
                }

                override fun onPlaceCashOrder(
                    platform: BackstagePlatform,
                    transId: String,
                    orderId: String,
                    orderNumber: String,
                    goodId: String,
                    coins: String,
                    money: String
                ) {
                    placeCashOrderSuccessed(platform, transId, orderId, orderNumber, 0, goodId, coins, money)
                }

                override fun onPostRegData(regDataList: MutableList<RegDataBean>) {
                    REG_EVENT = 0
                    lifecycleScope.launch (Dispatchers.IO){
                        do {
//                            EventBus.getDefault().post(DevRegisterEvent(it, tips, 0, true))
                            EventBus.getDefault().post(DevRegisterEvent(regDataList))
                            delay(1000)
                        }while (REG_EVENT != 1)
                    }
                }

                override fun onWriteOffResult(platform: BackstagePlatform, writeOffResp: Any) {
                    EventBus.getDefault().post(WirteOffResultEvent(platform, writeOffResp))
                }

                override fun onUpgrade(fileId: String, name: String, url: String) {
                    //跳转更新页面
                    isDeviceIdle(0, fileId, url)
                }

                override fun onUploadLog(logType: Int, logNumber: String) {
                    mPresenter?.uploadLog(logType, logNumber)
                }
            }
        )
    }

    private fun refreshDevNumber(devNumber: String){
        SPHelper.setDeviceNumber(devNumber)
        EventBus.getDefault().post(RefreshDeviceNumberEvent(devNumber))
    }

    /**
     * 开启串口
     */
    private fun initSerialPort() {

//        initCoinController()

        initEggController()

        initBanknoteController()

        initBackscanController()

        scanGunHelper = ScanGunHelper().apply {
            setScanGunListener { msg ->
                logFile("USB扫码器接收数据：$msg")
                receivedScanData(msg)
            }
        }

    }

    private fun initEggController(){
        if (eggController != null){
            return
        }
        eggController = LyyEggController(
            "/dev/" + Constant.PORT_COIN,//控制板串口号
            //控制板串口号
            SerialPort.BAUDRATE.B38400,//波特率
            //波特率
            SerialPort.STOPB.B1,//停止位
            //停止位
            SerialPort.DATAB.CS8,//数据为
            //数据为
            SerialPort.PARITY.NONE,//校验位
            //校验位
            true,//开启控制板心跳
            object : LyyEggController.LyyEggListener{
                override fun heartBeat(isConnect: Boolean) {
                    if (Constant.COINCONTROL_HEARTBEAT != isConnect){
                        logFile("硬币控制板连接状态改变：${if (isConnect) "连接中" else "断开"}")
//                        mPresenter?.controlBoardConnectChange(ControlBoard.WHM_COIN, isConnect)
                    }
                    Constant.COINCONTROL_ERR_CODE = -1
                    Constant.COINCONTROL_STATE_CODE = -1
                    Constant.COINCONTROL_HEARTBEAT = isConnect
                    EventBus.getDefault().post(
                        ControllerHeartBeatEvent(
                            isConnect,
                            "-1",
                            "-1"
                        )
                    )
                }

                override fun outResult(success: Boolean, sn: String, msg: String) {
                    logFile("出货${if (success) "成功" else "失败"}：$sn $msg")
                    mPresenter?.recOutResult(success)
                }
            }
        )
    }

    private fun initCoinController() {
        try {
            if (coinController != null) {
                return
            }

            val type = SPHelper.getControlType()

            var coinParam: CoinControlParam? = null
            var coinFixParam: CoinControlFixParam? = null
            var whmLyyParam: WhmLyyParam? = null
            var whmAndroidParam: WhmAndroidParam? = null

            when (type) {
                0 -> whmLyyParam = WhmLyyParam(
                    "/dev/" + Constant.PORT_COIN,//控制板串口号
                    //控制板串口号
                    SerialPort.BAUDRATE.B38400,//波特率
                    //波特率
                    SerialPort.STOPB.B1,//停止位
                    //停止位
                    SerialPort.DATAB.CS8,//数据为
                    //数据为
                    SerialPort.PARITY.NONE,//校验位
                    //校验位
                    true//开启控制板心跳
                )

                1 -> whmAndroidParam = WhmAndroidParam(
                    country,
                    "/dev/" + Constant.PORT_COIN,
//                SerialPortParamUtil.getBaudrate(BuildConfig.COIN_BAUDRATE),
                    SerialPort.BAUDRATE.B115200,
                    SerialPort.STOPB.B1,
                    SerialPort.DATAB.CS8,
                    SerialPort.PARITY.NONE,
                )
            }

            coinController = CoinManager(
                coinParam,
                coinFixParam,
                whmLyyParam,
                whmAndroidParam,
                object : CoinManager.OnCoinListener {
                    override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
                        if (Constant.COINCONTROL_HEARTBEAT != isConnect){
                            logFile("硬币控制板连接状态改变：${if (isConnect) "连接中" else "断开"}")
                            mPresenter?.controlBoardConnectChange(ControlBoard.WHM_COIN, isConnect)
                        }
                        Constant.COINCONTROL_ERR_CODE = errCode
                        Constant.COINCONTROL_STATE_CODE = stateCode
                        Constant.COINCONTROL_HEARTBEAT = isConnect
                        EventBus.getDefault().post(
                            ControllerHeartBeatEvent(
                                isConnect,
                                stateCode.toString(),
                                errCode.toString()
                            )
                        )
                    }

                    override fun countErr(orderNumber: String, count: Long) {
                        logFile("出币数异常，不能出币：$count")
                    }

                    override fun motorTimeout(orderNumber: String, motorNumber: Int) {
                        logFile("马达$motorNumber 超时")
                    }

                    override fun onClearCoin(
                        orderNumber: String,
                        clearFinish: Boolean,
                        clearCoinCount: Long
                    ) {
                        logFile("清币${if (clearFinish) "结束：$clearCoinCount" else "中：$clearCoinCount"}")
                        clearCoins = clearCoinCount
                        clearCoinsFinish = clearFinish
                    }

                    override fun outCoinFinish(
                        orderNumber: String,
                        remainCount: Long,
                        currentOutCount: Long,
                        outFinish: Boolean
                    ) {
                        logFile("出币结束，未出币数：$remainCount 已出币数：$currentOutCount")
                        sendOutFinish(currentOutCount.toString(), remainCount.toString(), true, outFinish)
                    }

                    override fun onMotorErr(orderNumber: String, motorNumber: Int) {
                        logFile("马达$motorNumber 异常")
                    }

                    override fun saveCoinFinish(orderNumber: String, count: Long) {
                        logFile("存币结束，币数：$count")
                    }

                    override fun onCoinRefresh(
                        orderNumber: String,
                        coinCount: Long,
                        remainCount: Long,
                        outOrSave: Boolean
                    ) {
                        logFile("剩余未出币数：" + remainCount + if (outOrSave) " 出币" else " 存币")
                        sendOutFinish(coinCount.toString(), remainCount.toString(), outOrSave, false)
                    }

                    override fun onOutRec() {
                        logFile("控制板响应收到出币指令")
                    }

                    override fun onOutResult(msg: String) {
                        logFile(msg)
                    }

                    override fun onRecCashData(cash: Long, coins: Long) {
                        mPresenter?.saveCashData(cash, coins)
                    }

                    override fun onRecBasicConfig(basicConfigHex: String) {
                        if (respBasicConfigSnHex.isNotEmpty()){
                            val snHex = respBasicConfigSnHex
                            val cmdHex = "02"
                            val aHex = basicConfigHex.substring(0, 8)
                            val dispenser1ProportionHex = ByteUtil.long2HexStr("${basicConfigHex.substring(10, 12)}${basicConfigHex.substring(8, 10)}".toLong(16), 4, false)
                            val dispenser2StateHex = basicConfigHex.substring(12, 14)
                            val dispenser2ProportionHex = ByteUtil.long2HexStr("${basicConfigHex.substring(16, 18)}${basicConfigHex.substring(14, 16)}".toLong(16), 4, false)
                            val bHex = basicConfigHex.substring(18, 22)
                            val cashProportionHex = ByteUtil.long2HexStr("${basicConfigHex.substring(24, 26)}${basicConfigHex.substring(22, 24)}".toLong(16), 4, false)
                            val verHex = ByteUtil.str2HexStr("0", 16)
                            val countryHex = basicConfigHex.substring(basicConfigHex.length - 2)
                            val result = "$cmdHex$aHex$dispenser1ProportionHex$dispenser2StateHex$dispenser2ProportionHex$bHex$cashProportionHex$verHex$countryHex"

                            backstageManager?.respTransmissionNumber(snHex, result)
                            respBasicConfigSnHex = ""
                        }else{
                            EventBus.getDefault().post(RecBasicConfigEvent(basicConfigHex))
                        }
                    }

                    override fun onRecCashConfig(cashConfigHex: String) {
                        if (respCashConfigSnHex.isNotEmpty()){
                            val snHex = respCashConfigSnHex
                            val cmdHex = "04"
                            var result = ""
                            for (i in cashConfigHex.indices step 4){
                                val tempHex = cashConfigHex.substring(i, i + 4)
                                val cash = "${tempHex.substring(2, 4)}${tempHex.substring(0, 2)}".toLong(16)
                                val enableHex = if (cash == 0L) "00" else "01"
                                val itemHex = ByteUtil.long2HexStr(cash, 6, false)
                                result = "$result$enableHex$itemHex"
                            }

                            backstageManager?.respTransmissionNumber(snHex, "$cmdHex$result")
                            respCashConfigSnHex = ""
                        }else{
                            EventBus.getDefault().post(RecCashConfigEvent(cashConfigHex))
                        }
                    }

                    override fun onRecMotorConfig(motorConfigHex: String) {
                        if (respMotorConfigSnHex.isNotEmpty()){
                            val snHex = respMotorConfigSnHex
                            val cmdHex = "06"

                            backstageManager?.respTransmissionNumber(snHex, "$cmdHex$motorConfigHex")
                            respMotorConfigSnHex = ""
                        }else{
                            EventBus.getDefault().post(RecMotorConfigEvent(motorConfigHex))
                        }
                    }

                    override fun onMotorConfigResp(
                        forwardTimeoutHex: String,
                        reverseTimeoutHex: String,
                        stopDelayHex: String,
                    ) {
                        logFile("whmandroid控制板收到马达参数：forwardTimeoutHex=$forwardTimeoutHex reverseTimeoutHex=$reverseTimeoutHex stopDelayHex=$stopDelayHex")
                    }

                    override fun onGetMoney1(checkMoney: Long, totalMoney: Long) {
                        logFile("whm_android 纸钞机1允许接收纸钞 $checkMoney 接收纸钞后总金额 $totalMoney")
                        EventBus.getDefault().post(RefreshCashDataEvent(checkMoney, totalMoney))
                    }

                    override fun onRecieveMoney1(tempMoney: Long, checkMoney: Long) {
                        logFile("whm_android 纸钞机1校验纸钞 $checkMoney 当前总金额 $tempMoney")
                        mPresenter?.checkReceiveMoney(tempMoney, checkMoney)
                    }

                    override fun onGetMoney2(checkMoney: Long, totalMoney: Long) {
                        logFile("whm_android 纸钞机2允许接收纸钞 $checkMoney 接收纸钞后总金额 $totalMoney")
                        EventBus.getDefault().post(RefreshCashDataEvent(checkMoney, totalMoney))
                    }

                    override fun onRecieveMoney2(tempMoney: Long, checkMoney: Long) {
                        logFile("whm_android 纸钞机2校验纸钞 $checkMoney 当前总金额 $tempMoney")
                        mPresenter?.checkReceiveMoney(tempMoney, checkMoney)
                    }

                    override fun onInCoin1(coins: Long) {

                    }

                    override fun onInCoin2(coins: Long) {

                    }

                    override fun onSaveCoin1(orderNumber: String, coins: Long) {
                        logFile("投币器1存币，订单号：$orderNumber 存币数：$coins")
                    }

                    override fun onSaveCoin2(orderNumber: String, coins: Long) {
                        logFile("投币器2投币，订单号：$orderNumber 存币数：$coins")
                        //创建现金订单并出币
                        mPresenter?.createOneCoinOrder(coins)
                    }

                    override fun onInCoin(coins1: Long, coins2: Long) {
                        logFile("投入硬币：coins1=$coins1 coins2=$coins2")
                    }
                }
            )

//            coinController = CoinController(
//                "/dev/" + Constant.PORT_COIN,//控制板串口号
//                //控制板串口号
//                SerialPort.BAUDRATE.B115200,//波特率
//                //波特率
//                SerialPort.STOPB.B1,//停止位
//                //停止位
//                SerialPort.DATAB.CS8,//数据为
//                //数据为
//                SerialPort.PARITY.NONE,//校验位
//                //校验位
//                true,//开启控制板心跳
//                1,
//                50
//            ).apply {
//                setSerialControllerListener(object : CoinController.SerialControllerListener{
//                    override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
//                        Constant.COINCONTROL_ERR_CODE = errCode
//                        Constant.COINCONTROL_STATE_CODE = stateCode
//                        Constant.COINCONTROL_HEARTBEAT = isConnect
//                        EventBus.getDefault().post(
//                            ControllerHeartBeatEvent(
//                                isConnect,
//                                stateCode.toString(),
//                                errCode.toString()
//                            )
//                        )
//                    }
//
//                    override fun countErr(count: Long) {
//                        logFile("出币数异常，不能出币：$count")
//                    }
//
//                    override fun motorTimeout(motorNumber: Int) {
//                        logFile("马达$motorNumber 超时")
//                    }
//
//                    override fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long) {
//                        logFile("清币${if (clearFinish) "结束：$clearCoinCount" else "中：$clearCoinCount"}")
//                        clearCoins = clearCoinCount
//                        clearCoinsFinish = clearFinish
//                    }
//
//                    override fun outCoinFinish(
//                        remainCount: Long,
//                        currentOutCount: Long,
//                        outFinish: Boolean
//                    ) {
//                        logFile("出币结束，未出币数：$remainCount 已出币数：$currentOutCount")
//                        sendOutFinish(remainCount.toString(), true, outFinish)
//                    }
//
//                    override fun onMotorErr(motorNumber: Int) {
//                        logFile("马达$motorNumber 异常")
//                    }
//
//                    override fun saveCoinFinish(count: Long) {
//                        logFile("存币结束，币数：$count")
//                    }
//
//                    override fun onCoinRefresh(coinCount: Long, outOrSave: Boolean) {
//                        logFile("剩余未出币数：" + coinCount + if (outOrSave) " 出币" else " 存币")
//                        sendOutFinish(coinCount.toString(), outOrSave, false)
//                    }
//
//                    override fun onOutRec() {
//                        logFile("控制板响应收到出币指令")
//                    }
//
//                    override fun onOutResult(msg: String) {
//                        logFile(msg)
//                    }
//                })
//            }
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("打开出币控制板异常：${e.message}")
        }
    }

    private fun initBanknoteController() {
        try {
            if (banknoteController != null) {
                return
            }
            banknoteController = BanknoteController(
                //控制板类型
                "/dev/" + Constant.PORT_BANKNOTE,//控制板串口号
                //控制板串口号
                SerialPort.BAUDRATE.B9600,//波特率
                //波特率
                SerialPort.STOPB.B1,//停止位
                //停止位
                SerialPort.DATAB.CS8,//数据为
                //数据为
                SerialPort.PARITY.EVEN,//校验位
                object : BanknoteController.MoneyListener {
                    override fun getMoney(checkMoney: Long, totalMoney: Long) {
                        mPresenter?.saveMoney(checkMoney, totalMoney)
                    }

                    override fun recieveMoney(tempMoney: Long, checkMoney: Long) {
                        mPresenter?.checkReceiveMoney(tempMoney, checkMoney)
                    }
                }
            )
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("打开纸钞机异常：${e.message}")
        }
    }

    private fun initBackscanController() {
        try {
            if (backscanController != null) {
                return
            }
            backscanController = BackscanController(
                //控制板类型
                "/dev/" + Constant.PORT_BACKSCAN,//控制板串口号
                //控制板串口号
                SerialPort.BAUDRATE.B9600,//波特率
                //波特率
                SerialPort.STOPB.B1,//停止位
                //停止位
                SerialPort.DATAB.CS8,//数据为
                //数据为
                SerialPort.PARITY.NONE,//校验位
                object : BackscanController.BackscanListener {
                    override fun onReceive(data: String) {
                        if (!isHandlingData()) {
                            logFile("反扫数据处理中：$data")
                            return
                        }
                        backscanController?.stopScan()
                        logFile("收到反扫数据：$data")
                        receivedScanData(data)
                    }
                }
            )

            //启动后打开反扫
            openScan(true)
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("打开反扫器异常：${e.message}")
        }
    }

    /**
     * 检查是否有异常订单需要补币
     */
    private fun checkSupplement(){
        if (getDeviceStatus()) return
        val endDate = DateTimeUtil.nowDate
        val startDate = DateTimeUtil.getDaysAgoDate(7)
        mPresenter?.getOrderSupplement(startDate, endDate)
    }

    private fun loopRefreshClearData() {
        val clearCoinsJob = lifecycleScope.launch(Dispatchers.IO) {
            withContext(Dispatchers.IO) {
                val uuid = clearOrderNumber
                while (!clearCoinsFinish) {
                    delay(1000)
                    mPresenter?.clearCoins(uuid, clearCoins)
                    EventBus.getDefault()
                        .post(ClearCoinsEvent(clearCoins.toString(), clearCoinsFinish))
                }
                //清币结束
                EventBus.getDefault()
                    .post(ClearCoinsEvent(clearCoins.toString(), clearCoinsFinish))
                EventBus.getDefault().post(StopClearCoinsEvent())
                mPresenter?.clearCoins(uuid, clearCoins)
                delay(500)
                //发送指令，重置马达状态
                coinController?.resetMotor()
            }
        }
    }

    private fun createLyySdkParam(deviceId: String): LyySdkParam {
        return LyySdkParam(
            BuildConfig.LYYSDK_APPID,// 1c78874465a4ec86
            BuildConfig.LYYSDK_SECRET,// 33f993659af53d02226e279c39002d94
            BuildConfig.LYYSDK_HOST,
            BuildConfig.LYYSDK_PORT,
            deviceId,
            BuildConfig.LYYSDK_TYPE,
            BuildConfig.LYYSDK_LOGINFLAG// 5850
        )
    }

    private fun createLyyBoxParam(deviceId: String): LyyBoxParam {
        return LyyBoxParam(
            deviceId,
            BuildConfig.LYYBOX_PORTNAME,
            CommonUtil.getBaudrate(BuildConfig.LYYBOX_BAUDRATE),
            CommonUtil.getStopb(BuildConfig.LYYBOX_STOPB),
            CommonUtil.getDatab(BuildConfig.LYYBOX_DATAB),
            CommonUtil.getParity(BuildConfig.LYYBOX_PARITY),
            BuildConfig.LYYBOX_LOGINFLAG.toInt()
        )
    }

    private fun createWhmMqttHexParam(deviceId: String): WhmMqttHexParam {
        return WhmMqttHexParam(
            BuildConfig.WHM_MQTT_HEX_PROTOCOL,
            deviceId,
//            BuildConfig.WHM_MQTT_HEX_HARDWARE_CODE,//测试用
            "",
            BuildConfig.WHM_MQTT_HEX_USER_NAME,
            BuildConfig.WHM_MQTT_HEX_PASSWORD,
            BuildConfig.WHM_MQTT_HEX_HOST,
            BuildConfig.WHM_MQTT_HEX_AUTH_HOST,
            BuildConfig.WHM_MQTT_HEX_PLATFORM_CODE,
            BuildConfig.WHM_MQTT_HEX_COMMON_KEY,
            BuildConfig.WHM_MQTT_HEX_PRIVATE_KEY,
        )
    }

    private fun createYchSdkParam(deviceId: String): YchSdkParam {
        val appName = applicationContext.packageName.split(".")[2]
        val mainBoardNumber = Build.HOST + "-" + deviceId
//        val mainBoardNumber = "002F0002"
        val devType = "0x002F0002"
        return YchSdkParam(
//            "YZYjkVnSvfyREWz0lTzzHtiZw9",//签名
            "oXeu43r0c0nAVG2wzSeiA8",//未签名
            deviceId,
            1,
            "1",
            devType,
            appName,
            BuildConfig.VERSION_CODE,
            "0.0.0.0",
            "255.255.255.0",
            "0.0.0.0",
        )
    }

    private fun createKkbSdkParam(deviceId: String): KkbSdkParam {
        val appName = applicationContext.packageName.split(".")[2]
        val mainBoardNumber = Build.HOST + "-" + deviceId
//        val mainBoardNumber = "002F0002"
        val devType = "0x002F0002"
        val identity = kkbIdentity
        return KkbSdkParam(
//            "YZYjkVnSvfyREWz0lTzzHtiZw9",//签名
            identity,//未签名
            deviceId,
            1,
            "1",
            devType,
            appName,
            BuildConfig.VERSION_CODE,
            "0.0.0.0",
            "255.255.255.0",
            "0.0.0.0",
            false
        )
    }

    /**
     * 发射收到反扫数据
     * @param scanData 反扫数据
     */
    private fun receivedScanData(scanData: String) {
        canScan = false
//        EventBus.getDefault().post(ReceivedScanDataEvent(scanData))
        mPresenter?.receiveScanOrder(scanData)
    }

    private fun sendOutFinish(
        realCoins: String,
        remainCoins: String,
        outOrSave: Boolean,
        isFinish: Boolean,
        success: Boolean = true
    ) {
        when (outMode){
            OutMode.NORMAL -> {
                EventBus.getDefault()
                    .post(RefreshCoinsEvent(realCoins, remainCoins, outOrSave, isFinish, success))
            }
            OutMode.SUPPLEMENT_FRAGMENT -> {
                EventBus.getDefault()
                    .post(SupplementEvent(realCoins, remainCoins, outOrSave, isFinish, success))
            }
            OutMode.SUPPLEMENT_ACTIVITY -> {
                supplementDialog?.let {
                    lifecycleScope.launch(Dispatchers.Main) {
                        it.refreshInfo(remainCoins, isFinish, success)
                    }
                }
            }
        }

    }

    private fun placeOrderSuccessed(platform: BackstagePlatform, transId: String, orderId: String, orderNumber: String, status: Int, goodId: String, coins: String, money: String){
        if (coins.isEmpty() && money.isEmpty()){
            logFile("下单数据1 transId=$transId orderId=$orderId orderNumber=$orderNumber")
            EventBus.getDefault()
                .post(PlaceOrderEvent(platform, transId, orderId, orderNumber, status))
        }else {
            //下单，保存订单数据
            logFile("下单数据2 transId=$transId orderId=$orderId orderNumber=$orderNumber")
            mPresenter?.insertHttpOrder(platform, transId, orderId, orderNumber, goodId, coins, money)
            //通知kkbPayDialog orderId，用于取消查询订单状态
            if (platform == BackstagePlatform.KKB){
                EventBus.getDefault()
                    .post(PlaceOrderEvent(platform, transId, orderId, orderNumber, status))
            }
        }
    }

    private fun placeCashOrderSuccessed(platform: BackstagePlatform, transId: String, orderId: String, orderNumber: String, status: Int, goodId: String, coins: String, money: String){
        logFile("KKB现金下单完成")
    }

    private fun doOutCoins(coins: Long, uuid: String){
        try {
            coinController?.run {
                if (!getConnectState()) {
                    logFile("控制板链接中断，出币失败")
                    sendOutFinish("0", coins.toString(), true, true, false)
                    return
                }
                val orderNumber = uuid
                when (SPHelper.getMotorType()) {
                    Constant.MOTOR_TYPE_SINGLE_1 -> {
                        logFile("马达1出币")
                        outCoinM1Business(orderNumber, coins)
                    }

                    Constant.MOTOR_TYPE_SINGLE_2 -> {
                        logFile("马达2出币")
                        outCoinM2Business(orderNumber, coins)
                    }

                    Constant.MOTOR_TYPE_ALTERNATELY -> {
                        logFile("马达交替出币")
                        outCoinAlternately(orderNumber, coins)
                    }

                    Constant.MOTOR_TYPE_ASYNCHRONIZATION -> {
                        logFile("马达同时出币")
//                            it.doubleOutCoinBusiness(outCount.toLong())
                    }

                    else -> {
                        logFile("未知出币模式")
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("处理出币异常：${e.message}")
        }
    }

    /**
     * 显示异常订单补币窗口
     */
    private fun showSupplementDialog(datas: MutableList<SupplementOrderBean>){
        try {
            supplementDialog?.dismissAllowingStateLoss()

            supplementDialog = SupplementDialog(
                datas, object : SupplementDialog.SupplementDialogListener {
                    override fun dismiss() {
                        logFile("异常订单补币窗口关闭")
                        supplementDialog = null

                    }

                    override fun back() {
                        logFile("异常订单补币窗口点击返回")
                    }

                    override fun supplement(orderNumber: String, coins: Long) {
                        //处理异常补币订单
                        outMode = OutMode.SUPPLEMENT_ACTIVITY
                        doOutCoins(coins, orderNumber)
                    }

                    override fun setRealAmount(id: Long, realAmount: Long) {
                        //更新订单实际出币数量
                        mPresenter?.setRealAmount(id, realAmount.toString())
                    }

//                    override fun saveCoins(orderNumber: String, userId: String, transId: String) {
//                        logFile("校验存币订单数据：orderNumber=$orderNumber userId=$userId transId=$transId")
//                        saveCoin(orderNumber, userId, false)
//                        mPresenter?.checkSaveCoins(orderNumber, userId, transId)
//                    }
                })
            supplementDialog?.showNow(supportFragmentManager, "SupplementDialog")
        }catch (e: Exception){
            e.printStackTrace()
            logFile("显示异常订单补币窗口异常：${e.message}")
        }
    }

    private fun isDeviceIdle(type: Int, verName: String, url: String){
        checkDevJob?.cancel()

        checkDevJob = lifecycleScope.launch {
            devIdle = false
            do {
                EventBus.getDefault().post(GetDeviceIdleEvent(0))
                delay(1000)
            }while (!devIdle)

            when (type){
                0 -> {
                    //更新APP
                    startActivity(Intent(this@MainActivity, UpgradeActivity::class.java).apply {
                        putExtra("downloadUrl", url)
                        putExtra("verName", verName)
                    })
                    finish()
                }
                1 -> {
                    //重启
                    logFile("重启系统")
                    BoardApiUtil.rebootSystem()
                }
            }

        }
    }

    private fun openScan(open: Boolean){
        if (open) {
            //开启反扫
            backscanController?.startScan()
            canScan = true
        } else {
            backscanController?.stopScan()
            canScan = false
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun switchFragmentEvent(event: SwitchFragmentEvent) {
        showFragment(event.index)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun exitEvent(event: ExitAppEvent) {
        exit()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun getPayCodeEvent(event: GetPayCodeEvent) {
        logFile("获取支付二维码事件")
        backstageManager?.getPayQrCode(event.reqData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun postResultEvent(event: PostResultEvent) {
        logFile("上报启动结果事件")
        backstageManager?.reportOutResult(event.reqData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun startClearCoinsEvent(event: StartClearCoinsEvent) {
        logFile("开始清币事件")
        clearOrderNumber = DateTimeUtil.nowDateTimeSp
        mPresenter?.creatClearOrder(clearOrderNumber)
        clearCoins = 0
        clearCoinsFinish = false
        coinController?.clearCoinAlternately()
        loopRefreshClearData()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun outCoinsEvent(event: OutCoinsEvent) {
        logFile("发送出币指令事件")
        outMode = OutMode.NORMAL
        doOutCoins(event.coins, event.k)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun supplementCoinsEvent(event: SupplementCoinsEvent) {
        logFile("异常订单补币事件:${event.coins}")
        //先发送重置马达指令，再发送出币指令
        lifecycleScope.launch {
            coinController?.resetMotor()
            delay(500)
            outMode = OutMode.SUPPLEMENT_FRAGMENT
            doOutCoins(event.coins, event.k)
        }
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun scanEvent(event: ScanEvent) {
        logFile("反扫器${if (event.enable) "开启" else "关闭"} 事件")
        openScan(event.enable)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun postBackscanPayEvent(event: PostBackscanPayEvent) {
        logFile("上报反扫数据事件")
        backstageManager?.postBackscan(event.reqData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun banknoteEvent(event: BanknoteEvent) {
        logFile("纸钞机事件：${event.open}")
        banknoteController?.startInMoney(event.open)
        coinController?.startInMoney(event.open)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun postCashEvent(event: PostCashEvent) {
        logFile("上报纸钞数据事件：${GsonUtil.getInstance()!!.toJson(event.repData)}")
        backstageManager?.uploadCoinListAdd(event.repData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun saveBasicConfigEvent(event: SaveBasicConfigEvent) {
        logFile("发送指令设置基础配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.setBasicConfig(event.configHex)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun saveCashConfigEvent(event: SaveCashConfigEvent) {
        logFile("发送指令设置纸钞通道配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.setCashConfig(
            CashConfigBean(
            event.configHex.substring(0, 4) != "0000",
                "${event.configHex.substring(2, 4)}${event.configHex.substring(0, 2)}".toLong(16),

                event.configHex.substring(4, 8) != "0000",
                "${event.configHex.substring(6, 8)}${event.configHex.substring(4, 6)}".toLong(16),

                event.configHex.substring(8, 12) != "0000",
                "${event.configHex.substring(10, 12)}${event.configHex.substring(8, 10)}".toLong(16),

                event.configHex.substring(12, 16) != "0000",
                "${event.configHex.substring(14, 16)}${event.configHex.substring(12, 14)}".toLong(16),

                event.configHex.substring(16, 20) != "0000",
                "${event.configHex.substring(18, 20)}${event.configHex.substring(16, 18)}".toLong(16),

                event.configHex.substring(20, 24) != "0000",
                "${event.configHex.substring(22, 24)}${event.configHex.substring(20, 22)}".toLong(16),

                event.configHex.substring(24, 28) != "0000",
                "${event.configHex.substring(26, 28)}${event.configHex.substring(24, 26)}".toLong(16),

                event.configHex.substring(28, 32) != "0000",
                "${event.configHex.substring(30, 32)}${event.configHex.substring(28, 30)}".toLong(16),

                event.configHex.substring(32, 36) != "0000",
                "${event.configHex.substring(34, 36)}${event.configHex.substring(32, 34)}".toLong(16),

                event.configHex.substring(36, 40) != "0000",
                "${event.configHex.substring(38, 40)}${event.configHex.substring(36, 38)}".toLong(16),
        ))
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun saveMotorConfigEvent(event: SaveMotorConfigEvent) {
        logFile("发送指令设置马达配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        val forward = event.configHex.substring(0, 2).toInt(16)
        val reverse = event.configHex.substring(2, 4).toInt(16)
        val stopDelay = event.configHex.substring(4, 6).toInt(16)
        coinController?.setMotorConfig(forward, reverse, stopDelay)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun refreshBasicConfigEvent(event: RefreshBasicConfigEvent) {
        logFile("发送指令刷新基础配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.getBasicConfig()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun refreshCashConfigEvent(event: RefreshCashConfigEvent) {
        logFile("发送指令刷新纸钞通道配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.getCashConfig()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun refreshMotorConfigEvent(event: RefreshMotorConfigEvent) {
        logFile("发送指令刷新马达配置事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.getMotorConfig()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun getLoginCodeEvent(event: GetLoginCodeEvent) {
        logFile("获取设备登录二维码事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.getLoginCode()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun queryPlaceOrderCancelEvent(event: QueryPlaceOrderCancelEvent) {
        logFile("取消查询下单支付结果事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.queryPlaceOrderCancel(event.transId)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun queryLgLoginCancelEvent(event: QueryLgLoginCancelEvent) {
        logFile("取消查询会员扫码登录事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.queryLgLoginCancel()
        backstageManager?.logout()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun saveCoinEvent(event: SaveCoinEvent) {
        logFile("存币开关事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.saveCoinEnable(event.orderNumber, event.userId, event.open)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun getWithdrawalCodeEvent(event: GetWithdrawalCodeEvent) {
        logFile("获取提币码事件")
        backstageManager?.getWithdrawalCode()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun postWriteOffDataEvent(event: PostWriteOffDataEvent) {
        logFile("上报核销数据事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.repWriteOffData(event.repData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun repSaveCoinDataEvent(event: RepSaveCoinDataEvent) {
        logFile("上报存币数据事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.uploadSaveCoinData(event.repData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun placeCashOrderEvent(event: PlaceCashOrderEvent) {
        logFile("纸钞下单事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.placeCashOrder(event.cashOrderData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun placeLocalWithdrawalOrderEvent(event: PlaceLocalWithdrawalOrderEvent) {
        logFile("本地提币下单事件：${GsonUtil.getInstance()!!.toJson(event)}")
        backstageManager?.placeLocalWithdrawalOrder(event.reqData)
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun resetMotorEvent(event: ResetMotorEvent) {
        logFile("重置马达状态事件：${GsonUtil.getInstance()!!.toJson(event)}")
        coinController?.resetMotor()
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    fun getDeviceIdleRespEvent(event: GetDeviceIdleRespEvent) {
        logFile("获取设备状态响应事件：${event}")
        devIdle = event.idle
    }
}